package idp;

import java.util.ArrayList;
import java.util.logging.Level;
import debuggen.Debug;
import net.java.games.input.Controller;
import net.java.games.input.ControllerEnvironment;
import Command.*;
import Communication.BoatDataWrapper;
import Communication.Communication;
import Dashboard.DashboardController;
import Database.Database;
import UserInput.*;

/**
 * Main
 * Start punt voor applicatie
 * @author Rick
 */
public class MainController {
	
	//USERINPUT
	private ArrayList<UserInput> inputDevices = new ArrayList<UserInput>();
	
	//DASHBOARD
	private DashboardController dashboardController = new DashboardController();
	
	//COMMUNICATION
	private Communication communication = new Communication(this);
	
	//DATABASE
	private Database database;
	
	//BOATDATA
	private BoatDataWrapper mainBoatData;
	
	private static MainController mainController = null;
	/**
	 * Constructor
	 * Singleton
	 */
	private MainController() {
		try
		{
			// Init boat data wrapper
			mainBoatData = new BoatDataWrapper();
			dashboardController.retreiveBoatInput(mainBoatData);
			
			// Add keyboard to arraylist for userinput
			inputDevices.add(new KeyboardInput(this));
			// dashboard input
			inputDevices.add(new DashboardInput(this));
			// Get joystick
			Controller c = getControllerJoystick();
			// If not connected, just skip
			if(c != null)
			{
				// Add joystick and start using it.
				inputDevices.add(new JoystickSideWinder(c, this));
				System.out.println("Joystick added!");
			} 
			// Init database
			database = new Database(this);
			
			//
			dashboardController.addInputListeners(inputDevices);
			
			
		}
		catch(ClassNotFoundException e)
		{ // Only throwed if database class can't load driver.
			System.out.println(e);
			
			// Write info to debug reader
			if(Debug.DEBUGGEN)
			{
				// Write record to logfile
				Debug.writeMessage("Class not found: MainController (Database)", Level.WARNING, e);
			}
		}
	}
	
	public void addJoytick(Controller p_cController)
	{
		ArrayList<UserInput> lijst = new ArrayList<UserInput>();
		lijst.add(new JoystickSideWinder(p_cController, this));
		dashboardController.addInputListeners(lijst);
	}
	/**
	 * getControllerJoystick
	 * Get the correct joystick controller
	 * @return Joystick SideWinder controller
	 */
	public Controller getControllerJoystick()
	{
		ControllerEnvironment ce = ControllerEnvironment.getDefaultEnvironment();
		Controller[] controllers = ce.getControllers();
		
		// Check for correct controller, so loop through array.
		for(int i = 0; i < controllers.length; i++)
			// Check for correct controller
			if(controllers[i].getName().contains(JoystickSideWinder.NAME))
				return controllers[i];
		
		// No correct controller found
		return null;
	}
	/**
	 * startBluetooth
	 * Start bt!
	 */
	public void startBluetooth()
	{
		communication.start();
	}
	/**
	 * stopBluetooth
	 * Stop bt
	 */
	public void stopBluetooth()
	{
		communication.stop();
	}
	/**
	 * getInstance
	 * @return
	 */
	public static MainController getInstance()
	{
		// Create new instance if maincontroller is null
		if(mainController == null)
		{
			mainController = new MainController();
		}
		return mainController;
	}
	
	
	
	/**
	 * Push input From boat to DashboardController
	 * @param data
	 */
	public void processInputFromBoat(BoatDataWrapper data) 
	{
		dashboardController.retreiveBoatInput(data);
		database.insertDataInSession(data);
	}

	/**
	 * Push input from user to DashboardController AND communication to boat
	 * @param command
	 */
	public void processUserInput(Command command)
	{
		// If command is NoCommand, ignore!
		if(command instanceof NoCommand || command == null)
		{
			return;
		}
		// Write info to textfield for debug
		dashboardController.writeLineToBox(command.getCommandString(), command);
		// Add data to wrapper, so gauges can be changed
		
		//addToBoatDataWrapper(command);
		// Process data to BT
		communication.processCommand(command);		
	}

	/**
	 * Process SessionID list from database to dashboardcontroller..
	 * @param sessionList
	 */
	public void processSessionIds(ArrayList<Integer> sessionList)
	{
		dashboardController.retreiveSessionIds(sessionList);
	}
	/**
	 * processReplayData
	 * Push data from database to dashboard controller
	 * @param data
	 */
	public void processReplayData(ArrayList<BoatDataWrapper> data, int frequency)
	{
		dashboardController.createReplay(data, frequency);
	}
	/**
	 * requestReplay
	 * Get data from database with given session id
	 * @param sessionID
	 */
	public void requestReplay(int sessionID, int frequency)
	{
		database.processReplayData(sessionID, frequency);		
	}	
	/**
	 * addToBoatDataWrapper
	 * Add information to boatdatawrapper
	 * @param p_cmdCommand
	 */
	public void addToBoatDataWrapper(Command p_cmdCommand)
	{
        // Write command info to textfield on dashboard
		dashboardController.writeLineToBox(p_cmdCommand.getCommandString(), p_cmdCommand);
		
		
		// Check which type of command is used
		if(p_cmdCommand instanceof NoCommand)
        {
            return;
        }
        else if(p_cmdCommand instanceof Gradient)
        {
            mainBoatData.setAngle(p_cmdCommand.getValue());
        }
        else if(p_cmdCommand instanceof Rudder)
        {
            mainBoatData.setRudderPosition(p_cmdCommand.getValue());
        }
        else if(p_cmdCommand instanceof WindDirection)
        {
            mainBoatData.setWindDirection(p_cmdCommand.getValue());
        }
        else if(p_cmdCommand instanceof Sail)
        {
            mainBoatData.setSailPosition(p_cmdCommand.getValue());
        }else if(p_cmdCommand instanceof EngineForward)
        {
        	mainBoatData.setMotor(2);
        }else if(p_cmdCommand instanceof EngineBackward)
        {
        	mainBoatData.setMotor(0);
        }else if(p_cmdCommand instanceof EngineOut)
        {
        	mainBoatData.setMotor(1);
        } else if (p_cmdCommand instanceof KeelUp)
        {
        	mainBoatData.setKeel(0);
        }else if(p_cmdCommand instanceof KeelDown)
        {
        	mainBoatData.setKeel(1);
        } else if(p_cmdCommand instanceof EmergencyStop)
        {
        	mainBoatData.setEmergencyStop(1);
        } else if(p_cmdCommand instanceof EmergencySituation)
        {
        	mainBoatData.setEmergencySituation(1);
        } else if(p_cmdCommand instanceof UndoEmergencySituation)
        {
        	mainBoatData.setEmergencySituation(0);
        }else if(p_cmdCommand instanceof ControlAutomatic)
        {
        	mainBoatData.setControlMethod(1);
        }else if(p_cmdCommand instanceof ControlManual)
        {
        	mainBoatData.setControlMethod(0);
        }
		
		// Handle input from the boat
		processInputFromBoat(mainBoatData);
	}
	/**
	 * setBluetoothConnectionIsActive
	 * Check if we have a working BT connection
	 * @param value - Boolean 
	 */
	public void setBluetoothConnectionIsActive(boolean value)
	{
		if (value)
			mainBoatData.setBluetoothConnection(1);
		else
			mainBoatData.setBluetoothConnection(0);
	}
	
	
	/**
	 * getDataWrapper
	 * @return BoatDataWrapper
	 */
	public BoatDataWrapper getDataWrapper()
	{
		return mainBoatData;
	}
	
	public void createDatabaseSession()
	{
		database.createSession();
	}
	
	public void resetDatabase()
	{
		database.deleteTables();
	}
	

	/**
	 * Start point application
	 */
	public static void main(String[] args)
	{
		MainController.getInstance();
	}
}
